package com.jocund.quicktest;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.locks.ReentrantLock;

// Conversation should be responsible for thread safe.
public class Conversation {
	
	public Conversation(){
		this.conversationId = 1; // TODO: Jimmy Mo - Hard coded
		this.group =  new DynamicGroup();
		this.historyMessages = new ArrayList<Message>();
		this.userMessageDict = new HashMap<String, BlockingQueue<Message>>();
	}
	
	private ReentrantLock lock = new ReentrantLock();
	
	private int conversationId;
	public int getConversationId(){
		return this.conversationId;
	}
	
	private List<Message> historyMessages;
	public void setHistoryMessages(List<Message> value){
		this.historyMessages = value;
	}
	public List<Message> getHistoryMessages(){
		return this.historyMessages;
	}
	
	//<UserUniqueName, BlockingQueue<Message>>
	private HashMap<String, BlockingQueue<Message>> userMessageDict;
	
	private DynamicGroup group;
	public void setGroup(DynamicGroup value){
		this.group = value;
	}
	public DynamicGroup getGroup(){
		return this.group;
	}
	
	public void pushMessage(String userUniqueName, Message msg) throws InterruptedException, UserExpiredException{
		if (!checkUserAlive(userUniqueName)){
			throw new UserExpiredException(userUniqueName + " expired!");
		}
		BlockingQueue<Message> userMessageQueue = this.userMessageDict.get(userUniqueName);
		userMessageQueue.put(msg);
	}
	
	public Message recvMessage(String userUniqueName) throws InterruptedException, UserExpiredException{
		if (!checkUserAlive(userUniqueName)){
			throw new UserExpiredException(userUniqueName + " expired!");
		}
		BlockingQueue<Message> userMessageQueue = this.userMessageDict.get(userUniqueName);
		int count = userMessageQueue.size();
		Message msg = null;
		if (count > 0)
			msg = userMessageQueue.take();

		return msg;
	}
	
	public void addUser(User user) throws DuplicationException, NotExistException{
		lock.lock();
		try{
			this.group.addUser(user);
			this.group.reportAlive(user.getUniqueName());
			BlockingQueue<Message> msgQueue = new ArrayBlockingQueue<Message>(1000);
			this.userMessageDict.put(user.getUniqueName(), msgQueue);
		}
		finally{
			lock.unlock();
		}
	}
	
	public synchronized void removeUser(String userUniqueName) throws NotExistException{
		lock.lock();
		try{
			this.group.removeUser(userUniqueName);
			this.userMessageDict.remove(userUniqueName);
		}
		finally{
			lock.unlock();
		}
	}
	
	public synchronized void reportUserAlive(String userUniqueName) throws NotExistException{
		User user = this.group.getUserMap().get(userUniqueName);
		this.group.reportAlive(user.getUniqueName());
	}
	
	// this method should keep naturally thread-safe.
	private boolean checkUserAlive(String userUniqueName){
		User user = this.group.getUserMap().get(userUniqueName);
		Calendar nowTime = Calendar.getInstance();
		nowTime.add(Calendar.MINUTE, -5); // TODO: Jimmy Mo - Hard coded
		Date expiredDate = (Date)nowTime.getTime();
		Date reportedDate = user.getLastReportedTime();
		if (reportedDate.before(expiredDate)){ //expired
			return false;
		}
		return true;
	}
}
